#include "iostream"
#include "fstream"
#include "Graph.hpp"
#include "UnDirGraph.hpp"
#include "DijkstraTable.hpp"
#include "string"
#include "sstream"
int count = 0; //计数器
void testDijkstraSingleFile(const std::string& filename)
{
    std::ifstream  file(filename);
    if (!file.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
    }

    std::string line;
    bool isVerticesSection = false;
    std::getline(file, line);
    int N = std::stoi(line);
    std::vector<int> nodes;
    for(int i =0 ;i < N;i ++ ){
        nodes.push_back(i);
    }
    Graph<int,int>G(nodes);
    std::map<int, int> vertices;

    while (std::getline(file, line)) {
        if (line == "----------\r") {
            isVerticesSection = true;
            continue;
        }
        std::istringstream iss(line);
        int v1, v2, d;
        char comma;
        if (!isVerticesSection) {
            // 读取边和权重
            if (!(iss >> v1 >> comma >> v2 >> comma >> d)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            G.addEdge(v1,v2,d);
        } else {
            // 读取顶点和权重
            if (!(iss >> v1 >> comma >> d)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            vertices[v1] = d;
        }

    }
    // 第二步
    auto table = G.createDijkstraTable(0,100000);
    // 第三步,对比.
    for(int i = 0 ; i < vertices.size();i ++ ){
        if(vertices[i] != table.dist(i)){
            return;
        }
    }
    file.close();
    std::cout << "第" << count << "次正确\n";
}


void testDijkstra(int MAX = 1000)
{
    // 测试Dijkstra算法的正确性.
    // 分为3步,1.首先利用C++将TestData中的数据导入
    // 2. 通过自己编写的函数得到Dijkstra表
    // 3. 对比实际的表格.如果匹配,则返回真,否则返回false
    count = 0;
    for(; count < MAX; count ++ ){
        std::string filename = "../TestData/DijkstraData/graph_" + std::to_string(count) + ".txt";
        testDijkstraSingleFile(filename);
    }

}

void testFloydSingleFile(const std::string& filename)
{
    std::ifstream  file(filename);
    if (!file.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
    }

    std::string line;
    bool isVerticesSection = false;
    std::getline(file, line);
    int N = std::stoi(line);
    std::vector<int> nodes;
    for(int i =0 ;i < N;i ++ ){
        nodes.push_back(i);
    }
    Graph<int,int>G(nodes);
    std::vector<std::vector<int>> mat_py;

    while (std::getline(file, line)) {
        if (line == "----------\r") {
            isVerticesSection = true;
            continue;
        }
        std::istringstream iss(line);
        int v1, v2, d;
        char comma;
        if (!isVerticesSection) {
            // 读取边和权重
            if (!(iss >> v1 >> comma >> v2 >> comma >> d)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            G.addEdge(v1,v2,d);
        } else {
            std::vector<int> row(N);
            std::stringstream ss(line);
            std::string value;
            for(int i = 0;i < N ; i ++){
                std::getline(ss, value, ',');
                row[i] = std::stoi(value);
            }
            mat_py.push_back(row);
        }
    }
    // 第二步
    auto mat_cpp = G.Floyd(); //返回一个Mat矩阵

    // 第三步,对比.
    for(int i = 0 ; i < mat_py.size();i ++ ){
        for(int j = 0; j < mat_py.size() ; j++){
            if(mat_py[i][j] != mat_cpp[i][j]){
                std::cerr << "匹配错误,出现在第" << count << "次\n";
            }
        }
    }
    file.close();
    std::cout << "第" << count << "次正确\n";
}

void testFloyd(int MAX = 1000)
{
    count = 0;
    for(; count < MAX; count ++ ){
        std::string filename = "../TestData/FloydData/graph_" + std::to_string(count) + ".txt";
        testFloydSingleFile(filename);
    }
}


void testPrimSingleFile(const std::string& filename)
{
    std::ifstream  file(filename);
    if (!file.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
    }

    std::string line;
    bool isVerticesSection = false;
    std::getline(file, line);
    int N = std::stoi(line);
    std::vector<int> nodes;
    for(int i =0 ;i < N;i ++ ){
        nodes.push_back(i);
    }
    UnDirGraph<int,int>G(nodes);
    UnDirGraph<int,int>T_py(nodes);


    while (std::getline(file, line)) {
        if (line == "----------\r") {
            isVerticesSection = true;
            continue;
        }
        std::istringstream iss(line);
        int v1, v2, d;
        char comma;
        if (!isVerticesSection) {
            // 读取边和权重
            if (!(iss >> v1 >> comma >> v2 >> comma >> d)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            G.addEdge(v1,v2,d);
        } else {
            if (!(iss >> v1 >> comma >> v2 >> comma >> d)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            T_py.addEdge(v1,v2,d);
        }
    }
    // 第二步
    auto T_cpp = G.Prim(); //返回一个Mat矩阵
    file.close();
    if ( T_py == T_cpp ){
        std::cout << "第" << count << "次正确\n";
    }else {
        std::cout << "先打印 py中生成的结果 : \n";
        T_py.print();
        std::cout << "再打印cpp中生成的结果 : \n";
        T_cpp.print();
        std::cerr << "错误\n";
    }

}

void testPrim(int MAX = 1000)
{
    count = 0;
    for(; count < MAX; count ++ ){
        std::string filename = "../TestData/PrimData/graph_" + std::to_string(count) + ".txt";
        testPrimSingleFile(filename);
    }
}

void testKruskalSingleFile(const std::string & filename)
{
    std::ifstream  file(filename);
    if (!file.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
    }

    std::string line;
    bool isVerticesSection = false;
    std::getline(file, line);
    int N = std::stoi(line);
    std::vector<int> nodes;
    for(int i =0 ;i < N;i ++ ){
        nodes.push_back(i);
    }
    UnDirGraph<int,int>G(nodes);
    int E_py;

    while (std::getline(file, line)) {
        if (line == "----------\r") {
            isVerticesSection = true;
            continue;
        }
        std::istringstream iss(line);
        int v1, v2, d;
        char comma;
        if (!isVerticesSection) {
            // 读取边和权重
            if (!(iss >> v1 >> comma >> v2 >> comma >> d)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            G.addEdge(v1,v2,d);
        } else {
            if (!(iss >> v1)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            E_py = v1;
        }
    }
    // 第二步
    auto T_cpp = G.Kruskal(); //返回一个无向图
    int E_cpp = T_cpp.sumWeight();

    file.close();
    if( E_py == E_cpp ){
        std::cout << "第" << count << "次正确\n";
    }else{
        std::cerr << "第" << count << "次错误\n";
    }

}

void testKruskal(int MAX = 1000)
{
    count = 0;
    for(; count < MAX; count ++ ){
        std::string filename = "../TestData/KruskalData/graph_" + std::to_string(count) + ".txt";
        testKruskalSingleFile(filename);
    }
}

void testDAGSingleFile(const std::string& filename)// 测试是 Directed Acyclic Graph
{
    std::ifstream  file(filename);
    if (!file.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
    }

    std::string line;
    bool isVerticesSection = false;
    std::getline(file, line);
    int N = std::stoi(line);
    std::vector<int> nodes;
    for(int i =0 ;i < N;i ++ ){
        nodes.push_back(i);
    }
    Graph<int,int>G(nodes);
    int flag_py; // 0表示false,1表示true

    while (std::getline(file, line)) {
        if (line == "----------\r") {
            isVerticesSection = true;
            continue;
        }
        std::istringstream iss(line);
        int v1, v2, d;
        char comma;
        if (!isVerticesSection) {
            // 读取边和权重
            if (!(iss >> v1 >> comma >> v2 >> comma >> d)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            G.addEdge(v1,v2,d);
        } else {
            if (!(iss >> v1)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            flag_py = v1;
        }
    }
    // 第二步
    int flag_cpp = G.isDGA(); //返回是不是有向无环图

    file.close();
    if( flag_py == flag_cpp ){
        std::cout << "第" << count << "次正确\n";
    }else{
        std::cout << "获取的图: \n";
        G.print();
        std::cerr << "第" << count << "次错误\n";
    }
}

void testDGA(int MAX = 1000)
{
    count = 0;
    for(; count < MAX; count ++ ){
        std::string filename = "../TestData/DGAData/graph_" + std::to_string(count) + ".txt";
        testDAGSingleFile(filename);
    }
}

void testFord_FulkersonSingleFile(const std::string& filename)// 测试是 Directed Acyclic Graph
{
    std::ifstream  file(filename);
    if (!file.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
    }

    std::string line;
    bool isVerticesSection = false;
    std::getline(file, line);
    int N = std::stoi(line);
    std::vector<int> nodes;
    for(int i =0 ;i < N;i ++ ){
        nodes.push_back(i);
    }
    Graph<int,int>G(nodes);
    int  maxFlow_py; // 0表示false,1表示true

    while (std::getline(file, line)) {
        if (line == "----------\r") {
            isVerticesSection = true;
            continue;
        }
        std::istringstream iss(line);
        int v1, v2, d;
        char comma;
        if (!isVerticesSection) {
            // 读取边和权重
            if (!(iss >> v1 >> comma >> v2 >> comma >> d)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            G.addEdge(v1,v2,d);
        } else {
            if (!(iss >> v1)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            maxFlow_py = v1;
        }
    }
    // 第二步
    int maxFlow_cpp = G.Ford_Fulkerson(0,N-1); //返回从顶点到初始点的最大流

    file.close();
    if( maxFlow_py == maxFlow_cpp ){
        std::cout << "第" << count << "次正确\n";
    }else{
        std::cout << "获取的图: \n";
        G.print();
        std::cerr << "第" << count << "次错误\n";
    }
}

void testFord_Fulkerson(int MAX = 1000)
{
    count = 0;
    for(; count < MAX; count ++ ){
        std::string filename = "../TestData/Ford_FulkersonData/graph_" + std::to_string(count) + ".txt";
        testFord_FulkersonSingleFile(filename);
    }
}

void testMaxMathchSingleFile(const std::string & filename)
{
    std::ifstream  file(filename);
    if (!file.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
    }

    std::string line;
    bool isVerticesSection = false;
    std::getline(file, line);
    int N = std::stoi(line);
    std::vector<int> nodes(N);
    std::iota(nodes.begin(),nodes.end(),0);
    Graph<int,int>G(nodes);
    int  maxMatch_py;

    while (std::getline(file, line)) {
        if (line == "----------\r") {
            isVerticesSection = true;
            continue;
        }
        std::istringstream iss(line);
        int v1, v2, d;
        char comma;
        if (!isVerticesSection) {
            // 读取边和权重
            if (!(iss >> v1 >> comma >> v2 >> comma >> d)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            G.addEdge(v1%N,v2%N,d);
        } else {
            if (!(iss >> v1)) {
                std::cerr << "格式错误: " << line << std::endl;
            }
            maxMatch_py = v1;
        }
    }

    // 第二步
    int maxMatch_cpp = G.HungarianAlgorithm(false); //返回从顶点到初始点的最大流
    //std::cout << "CPP 计算的结果是 : " << maxMatch_cpp << std::endl;
    file.close();
    if( maxMatch_py == maxMatch_cpp ){
        std::cout << "第" << count << "次正确\n";

    }else{
        std::cout << "获取的图: \n";
        std::cerr << "第" << count << "次错误\n";
    }
}

void testMaxMatch(int MAX = 1000)
{
    count = 0;
    for(; count < MAX; count ++ ){

        std::string filename = "../TestData/MaxMatchData/graph_" + std::to_string(count) + ".txt";
        testMaxMathchSingleFile(filename);
    }
}
